package treeview.unit;

import document.AttributeSet;
import document.Context;
import search.Visitor;

import java.awt.*;

/**
 * Created by Pavel Nikolaev
 */
public final class TextView extends ContextDependentView {
    private char[] mySource;
    private int myOffset;
    private int myLength;
    private AttributeSet myAttributeSet;
    private Font myFont;
    private FontMetrics myLastFontMetrics;

    public TextView(char[] source, int offset, int length, AttributeSet set, Context context) {
        super(context);
        this.mySource = source;
        this.myOffset = offset;
        this.myReferenceOffset = offset;
        this.myLength = length;
        this.myAttributeSet = set;
        this.myFont = myContext.getFont(myAttributeSet);
        this.myLastFontMetrics = null;
    }

    public void fitIntoWidth(Graphics g, int widthToFitInto) {
        FontMetrics fm = g.getFontMetrics(myContext.getFont(myAttributeSet));
        myHeight = fm.getHeight();
        myWidth = fm.charsWidth(mySource, myOffset, myLength);
        myDescent = fm.getDescent();
        myAscent = fm.getAscent();
        myLastFontMetrics = fm;
    }

    @Override
    public void print(int level) {
        for(int i = 0; i < level; ++i) System.out.print('\t');
        System.out.print("[");
        System.out.print(myWidth);
        System.out.print(" ");
        System.out.print(myHeight);
        System.out.print("] ");
        System.out.print(toString());
        System.out.print(" [");
        System.out.print(new String(mySource, myOffset, myLength));
        System.out.println("]");
    }


    public void paint(Graphics g) {
        Graphics cg = createComponentGraphics(g);
        int baseline_y = myY + myAscent;
        cg.drawChars(mySource, myOffset, myLength, myX, baseline_y);
        cg.dispose();
    }

    private Graphics createComponentGraphics(Graphics g) {
        Graphics componentGraphics = g.create();
        componentGraphics.setFont(myFont);
        return componentGraphics;
    }

    public void highlight(Graphics g, Color color) {
        Graphics cg = createComponentGraphics(g);
        cg.setColor(color);
        cg.fillRect(myX, myY, myWidth, myHeight);
        cg.dispose();
        paint(g);
    }

    @Override
    public void highlight(Graphics g, int startOffset, int endOffset, Color color) {
        if (startOffset >= endOffset) {
            paint(g);
            return;
        }

        int prefixLength =  startOffset - myOffset;
        if (prefixLength < 0) {
            startOffset = myOffset;
        }

        int suffixLength = myOffset + myLength - endOffset;
        if (suffixLength < 0) endOffset = myOffset + myLength;

        int highlightLength = endOffset - startOffset;
        int highlightX = (prefixLength <= 0) ?
                myX :
                myX + myLastFontMetrics.charsWidth(mySource, myOffset, prefixLength);
        int highlightWidth = myLastFontMetrics.charsWidth(mySource, startOffset, highlightLength);

        Graphics cg = createComponentGraphics(g);
        cg.setColor(color);
        cg.fillRect(highlightX, myY, highlightWidth, myHeight);
        cg.dispose();

        paint(g);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visitTextView(this);
    }

    @Override
    public int getStartOffset() {
        return myOffset;
    }

    @Override
    public int getEndOffset() {
        return myOffset + myLength;
    }

    @Override
    public int findOffset(int x) {
        if (myLastFontMetrics == null) return -1;
        int tempLocation = myX;
        int offset = myOffset;
        while ((offset < myOffset + myLength) && (tempLocation < x)) {
            tempLocation += myLastFontMetrics.charWidth(mySource[offset]);
            ++offset;
        }
        return (tempLocation < x) ? offset : offset - 1;
    }

    @Override
    public void setReferenceOffset(int offset) {
        //offset is ignored
    }
}
